创建表


# app文件夹下的 models.py

class Student(models.Model):
    id = models.AutoField(max_length=11, primary_key=True)
    name = models.CharField(max_length=11)

# SQL 语句

create table student(
    id int(11) auto_increment primary key,
    name varchar(11)
) engine=innodb default charset=utf8;

通过 ORM 创建/修改/删除表,都要执行两条命令


1. 通过 ORM 创建/修改/删除表,都要执行两条命令

  • 在cmd中执行

python manage.py makemigrations  # 记录 models.py 中所改动的内容
                                 # 所改动的记录都会保存在 app 文件夹下的 migrations 文件夹里
                                 # 如果不是通过 ORM 去修改数据库的表,而是直接通过数据库可视化工具去修改,肯定会报错,这时把 migrations 文件夹里的文件删掉(__init__.py 除外) 和 数据库中的所有表,重新执行这两条命令就可以了

python manage.py migrate  # 将 models.py 中的内容转换成SQL语句然后执行

  • 使用 Pycharm 中的 Run manage.py Task (在 Tools 里,快捷键: Ctrl+Alt+R),直接输入下面两个单词就可以了

makemigrations

migrate

  • 注意:

    • 当执行 python manage.py makemigrations 或 makemigrations 时,无法识别 app 中的 model ,只识别到 django 自带的 auth、admin、token 等表的时候,此时在 app 目录下创建一个 migrations 文件夹,然后里面放一个空的 __init__.py 文件即可

设置提示功能


1. 设置提示功能

  • 如果没有设置提示功能的前提下直接打印查询到的数据的时候,会直接显示一个内存地址或者是一个对象

# models.py

class Student(models.Model):
    username = models.CharField(max_length=10)
    age = models.IntegerField()

# views.py

def view_fn(request):
    student_data = Student.objects.all()
    student = Student.objects.get(id=1)

    print(student_data)  # <QuerySet [<Student: Student object>, <Student: Student object>, <Student: Student object>, <Student: Student object>]>
    print(student)  # Student object

    return render(request, 'index.html')

  • 使用类中的双下划线方法 __str__ 实现提示功能(不懂的可以看回面向对象中的 __str__ 方法)

# models.py

class Student(models.Model):
    username = models.CharField(max_length=10)
    age = models.IntegerField()
# 设置提示功能 -> python3 会执行 __str__
    def __str__(self):
        return 'username:{}, age:{}'.format(self.username, self.age)

# 设置提示功能 -> python3 会执行 __unicode__
    def __unicode__(self):
        return 'username:{}, age:{}'.format(self.username, self.age)

# views.py

def view_fn(request):
    student_data = Student.objects.all()
    student = Student.objects.get(id=1)

    print(student_data)  # <QuerySet [<Student: username:Yeung, age:23>, <Student: username:Kevin, age:18>, <Student: username:Eric, age:22>, <Student: username:Eric, age:22>]>
    print(student)  # username:Yeung, age:23

    return render(request, 'test.html')

字段


1. 常用的字段类

  • AutoField()
    • 自增整形字段
    • 必传参数: primary_key=True -> 设置为主键
    • 没有 AutoField() 字段时 Django 会自动帮你创建
    • 一个类中不能有两个 AutoField()

class TestTable(models.Model):
    id = models.AutoField(primary_key=True)

  • IntegerField()
    • int 类型
    • 数值范围: -2147483648 ~ 2147483647

class TestTable(models.Model):
    age = models.IntegerField(max_length=11)

  • CharField()
    • varchar 类型
    • 必传参数: max_length=num
    • max_length 表示字符长度

class TestTable(models.Model):
    name = models.CharField(max_length=15)

  • DateField()
    • date 类型
    • 日期格式: YYYY-MM-DD(1000-01-01 ~ 9999-12-31
    • 参数: 
      • auto_now = True/False -> 无论是添加数据还是修改数据,都会添加当前时间
      • auto_now_add = True/False -> 只有在添加数据的时候才会添加当前时间,修改不会
      • auto_now 和 auto_now_add 不能同时进行设置,下面只是为了演示

class TestTable(models.Model):
    this_date = models.DateField(auto_now=False, auto_now_add=True)

  • DatetimeField()
    • datetime 类型
    • 日期格式: YYYY-MM-DD HH:MM:SS(1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
    • 参数: 
      • auto_now = True/False -> 无论是添加数据还是修改数据,都会添加当前时间
      • auto_now_add = True/False -> 只有在添加数据的时候才会添加当前时间,修改不会
      • auto_now 和 auto_now_add 不能同时进行设置,下面只是为了演示

class TestTable(models.Model):
    this_date = models.DateTimeField(auto_now=False, auto_now_add=True)

  • TimeField()
    • time 类型
    • 日期格式: HH:MM:SS('-838:59:59' ~ '838:59:59'
    • 参数: 
      • auto_now = True/False -> 无论是添加数据还是修改数据,都会添加当前时间
      • auto_now_add = True/False -> 只有在添加数据的时候才会添加当前时间,修改不会
      • auto_now 和 auto_now_add 不能同时进行设置,下面只是为了演示

class TestTable(models.Model):
    this_date = models.TimeField(auto_now=False, auto_now_add=True)

  • DateField() 和 DatetimeField() TimeField() 的注意事项:

    • DateField() 和 DatetimeField() TimeField()所传的参数都是一样的

    • auto_now、auto_now_add 与 default 是互斥的,也就是说,当你把它三或者其中的两个放在一起就会报错,上面只是为了演示才写在一起

    • 当你将 auto_add_now 或者 auto_now 设置为 True 会引起 editable=False 和 blank=True(editable若为False,在admin界面或其他的表单(ModelForm)中则不会显示这一列的情况)

2. 字段类合集

  • 字段类型,详情可点击查询官网
分类
ORM字段类
说明
自增
AutoField()
  • int 类型的自增列
  • 必传参数: primary_key=True -> 设置为主键
BigAutoField()
  • bigint 类型的自增列
  • 必传参数: primary_key=True -> 设置为主键
布尔
BooleanField()
  • tinyint 类型
  • 布尔值
NullBooleanField()
  • tinyint类型
  • 可以为空的布尔值
字符
CharField()
  • varchar 类型
  • 必传参数: max_length=num
  • max_length 表示字符长度
TextField()
  • logtext 类型 -> 文本类型
数字
IntegerField()
  • int 类型 -> 整数
  • 数值范围: -2147483648 ~ 2147483647
PositiveIntegerField()
  • int 类型 -> 正整数
  • 数值范围: 0 ~ 2147483647
SmallIntegerField()
  • smallint 类型 -> 小整数
  • 数值范围: -32768 ~ 32767
PositiveSmallIntegerField()
  • smallint 类型 ->  正小整数
  • 数值范围: 0 ~ 32767
DecimalField()
  • decimal -> 十进制小数
  • 参数:
    • max_digits -> 小数总长度
    • decimal_places -> 小数位长度
BigIntegerField()
  • bigint 类型 -> 长整型
  • 数值范围: -9223372036854775808 ~ 9223372036854775807
FloatField()
  • double 类型 -> 双精度浮点数
日期
DateField()
  • date 类型
  • 日期格式: YYYY-MM-DD(1000-01-01 ~ 9999-12-31
  • 参数: 
    • auto_now = True/False -> 无论是添加数据还是修改数据,都会添加当前时间
    • auto_now_add = True/False -> 只有在添加数据的时候才会添加当前时间,修改不会
TimeField()
  • time 类型
  • 日期格式: HH:MM:SS('-838:59:59' ~ '838:59:59'
  • 参数: 
    • auto_now = True/False -> 无论是添加数据还是修改数据,都会添加当前时间
    • auto_now_add = True/False -> 只有在添加数据的时候才会添加当前时间,修改不会
DateTimeField()
  • datetime 类型
  • 日期格式: YYYY-MM-DD HH:MM:SS(1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
  • 参数: 
    • auto_now = True/False -> 无论是添加数据还是修改数据,都会添加当前时间
    • auto_now_add = True/False -> 只有在添加数据的时候才会添加当前时间,修改不会
DurationField()
  • bigint类型
  • 存储两个时间之间的时间差
  • ORM中获取的值为datetime.timedelta类型
文件
FileField()
  • varchar 类型
  • 路径保存在数据库,文件上传到指定目录
  • 参数:
    • upload_to = "" -> 上传文件的保存路径
    • storage = None -> 存储组件,默认django.core.files.storage.FileSystemStorage

ImageField()
  • varchar 类型
  • 路径保存在数据库,文件上传到指定目录
  • 参数:
    • upload_to = "" -> 上传文件的保存路径
    • storage = None -> 存储组件,默认django.core.files.storage.FileSystemStorage
    • width_field=None -> 上传图片的高度保存的数据库字段名(字符串)
    • height_field=None -> 上传图片的宽度保存的数据库字段名(字符串)

FilePathField()
  • varchar 类型
  • Django Admin以及ModelForm中提供读取文件夹下文件的功能
  • 参数:
    • path -> 文件夹路径
    • match=None -> 正则匹配
    • recursive=False -> 递归下面的文件夹
    • allow_files=True -> 允许文件
    • allow_folders=False -> 允许文件夹

进制
BinaryField()
  • longblob 类型 -> 二进制类型
IP
IPAddressField()
  • char(15)
  • Django Admin以及ModelForm中提供验证 IPV4 机制
GenericIPAddressField()
  • char(39)
  • Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
  • 参数:
    • protocol='both/ipv4,/ipv6',用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
    • unpack_ipv4=True/False, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"

其他
CommaSeparatedIntegerField()
  • varchar 类型
  • 格式必须为逗号分割的数字
SlugField()
  • varchar
  • Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
EmailField()
  • varchar
  • Django Admin以及ModelForm中提供验证机制
URLField()
  • varchar
  • Django Admin以及ModelForm中提供验证 URL
UUIDField()
  • char(32)
  • Django Admin以及ModelForm中提供对UUID格式的验证

3. ORM字段类与数据库实际的对应关系
分类
ORM字段类
mysql数据类型
自增
AutoField()
int
BigAutoField()
bigint
布尔
BooleanField()
tinyint
NullBooleanField()
tinyint
字符
CharField()
varchar
TextField()
logtext
数字
IntegerField()
int
PositiveIntegerField()
int
SmallIntegerField()
smallint
PositiveSmallIntegerField()
smallint
DecimalField()
decimal
BigIntegerField()
bigint
FloatField()
double
日期
DateField()
date
TimeField()
time
DateTimeField()
datetime
DurationField()
bigint
文件
FileField()
varchar
ImageField()
varchar
FilePathField()
varchar
进制
BinaryField()
longblob
IP
IPAddressField()
char(15)
GenericIPAddressField()
char(39)
其他
CommaSeparatedIntegerField()
varchar
SlugField()
varchar
EmailField()
varchar
URLField()
varchar
UUIDField()
char(32)

字段参数


1. 常用的字段类参数
字段参数
说明
null
  • 该字段是否可以为空(默认值: False)
  • null=True/False
default
  • 该字段的默认值
  • default='xxx'
unique
  • 是否建该字段设置为唯一索引(默认值: False)
  • unique=True/False
verbose_name
  • 设置该字段在 Admin 中所显示的字段名称
  • verbose_name='xxx'
blank
  • 该字段在Admin中是否允许用户输入为空(默认值: False)
  • blank=True/False
choices
  • Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
  • gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)

2. null 和 blank 的区别

  • blank : 针对于表单

    • 如果 blank=True,表示你的表单填写该字段的时候可以不填,比如 admin 界面下增加 model 一条记录的时候。直观的看到就是该字段不是粗体
    • 如果 blank=True,那么该字段在数据库上存储的是一个空字符串

  • null: 针对于数据库

    • 如果 null=True, 那么该字段在数据库上表现为 NULL,而不是一个空字符串

  • 注意: 日期型(DateField、TimeField、DateTimeField)和数字型(IntegerField、DecimalField、FloatField)不能接受空字符串,如要想要在填写表单的时候这两种类型的字段为空的话,则需要同时设置 null=True、blank=True;

# models.py

from django.db import models


class BlankNULL(models.Model):
    title = models.CharField(max_length=32)
    blank_true = models.CharField(max_length=12, blank=True)
    null_true = models.CharField(max_length=12, null=True)
    null_blank_true = models.CharField(max_length=12, blank=True, null=True)

# views.py

def home(request):
    blank_null = BlankNULL.objects.create(title='Kevin')
    print(blank_null.__dict__)  # {'null_blank_true': None, 'id': 3, 'blank_true': '', 'title': 'Kevin', 'null_true': None}
    return render(request, 'home.html')


3. 字段类的参数合集

  • 关于数据库的字段参数
字段参数
说明
null
  • 该字段是否可以为空(默认值: False)
  • null=True/False
db_column
  • 设置该字段在数据库的字段名
  • db_column='xxx'
default
  • 该字段的默认值
  • default='xxx'
primary_key
  • 是否将该字段设置为主键(默认值: False)
  • primary_key=True/False
db_index
  • 是否将该字段设置为普通索引(默认值: False)
  • db_index=True/False
unique
  • 是否将该字段设置为唯一索引(默认值: False)
  • unique=True/False
unique_for_date
  • 是否将字段【日期】部分设置为唯一索引(默认值: False)
  • unique_for_date = True/False
unique_for_month
  • 是否将字段【月】部分设置为唯一索引(默认值: False)
  • unique_for_month= True/False
unique_for_year
  • 是否将字段【年】部分设置为唯一索引(默认值: False)
  • unique_for_year= True/False

  • 关于Admin的字段参数
字段参数
说明
verbose_name
  • 设置该字段在 Admin 中所显示的字段名称
  • verbose_name='xxx'
blank
  • 该字段在Admin中是否允许用户输入为空(默认值: False)
  • blank=True/False
editable
  • 该字段中的内容在Admin中是否可以进行编辑(默认值: False)
  • editable=True/False
help_text
  • 设置该字段在Admin中的提示信息
  • help_text='xxx'
choices
  • Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
  • gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)

  • 关于错误信息和错误验证的字段参数

    • error_messages

      • 自定义错误信息(字典类型),从而定制想要显示的错误信息
      • key值: null, blank, invalid, invalid_choice, unique, unique_for_date
      • 如: {'null': "不能为空.", 'invalid': '格式错误'}

    • validators

      • 自定义错误验证(列表类型),从而定制想要的验证规则

from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator, MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator

# 如:

test = models.CharField(
    max_length=32,
    error_messages={
        'c1': '优先错信息1',
        'c2': '优先错信息2',
        'c3': '优先错信息3',
    },
    validators=[
        RegexValidator(regex='root_\d+', message='错误了', code='c1'),
        RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
        EmailValidator(message='又错误了', code='c3'), ]
)

4. 字段类参数的使用说明

  • choices 

    • choices 只作用于 Admin 和 ModelForm

    • 数据库中实际保存的是 choices 参数中 索引为0 的值,而通过Admin或ModelForm所生成的select标签显示的是 choices 参数中 索引为1 的值

    • 如果某个字段类配置了该参数,那么在Admin或ModelForm中都会以下拉框的形式显示

    • 一般 choices 参数的值都会单独拿出来放到一个变量中

    • 在CRM项目中有用到

class ChoicesTable(models.Model):
    education_choices = (
        (1, '重点大学'),
        (2, '普通本科'),
        (3, '独立院校'),
        (4, '民办本科'),
        (5, '大专'),
        (6, '民办专科'),
        (7, '高中'),
        (8, '其他')
    )
    education = models.IntegerField(verbose_name='学历', choices=education_choices, default=1)

 # 等同于

    # education = models.IntegerField(verbose_name='学历', choices=((1, '重点大学'), (2, '普通本科'), (3, '独立院校')), default=1)

    # ------------------------------------------------

    record_choices = (
        ('checked', "已签到"),
        ('vacate', "请假"),
        ('late', "迟到"),
        ('noshow', "缺勤"),
        ('leave_early', "早退"),
    )
    record = models.CharField(verbose_name="上课纪录", choices=record_choices, default="checked", max_length=64)

# 等同于

    # record = models.CharField(verbose_name="上课纪录", choices=(('checked', '已签到'), ('vacate', '请假'), ('late', '迟到')), default="checked", max_length=64)

  • limit_choices_to
    • 语法: limit_choices_to={'所关联表的字段名__条件': 'xxx'}

    • 作用: 根据 limit_choices_to 所设置的条件限制 admin 或 ModelForm 所生成的 select 标签中的内容

    • 只有一对多和多对多字段类才有该参数

    • limit_choices_to 只作用于 admin 或 ModelForm

    • 在CRM项目中有用到

# limit_choices_to={'所关联表的字段名__条件': 'xxx'}

# 班级表
class Classes(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=10)

    def __str__(self):
        return self.name


# 学生表
class Student(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=10)
    age = models.IntegerField()
    classes = models.ForeignKey(to='Classes', limit_choices_to={'id__in': [1, 2]})
# classes = models.ForeignKey(to='Classes', limit_choices_to={'id': 1})

    def __str__(self):
        return self.name

5.自定义字段类

  • 在Django的ORM中是没有 char 类型的字段类,需要自定义

class FixedCharField(models.Field):
"""
    自定义的char类型的字段类
    """
    def __init__(self, max_length, *args, **kwargs):
        super().__init__(max_length=max_length, *args, **kwargs)
        self.length = max_length

    def db_type(self, connection):
"""
        限定生成数据库表的字段类型为char,长度为length指定的值
        """
        return 'char(%s)' % self.length


class Class(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=25)
    cname = FixedCharField(max_length=25)  # 使用上面自定义的char类型的字段

元信息


ORM对应的类里面包含另一个Meta类,而Meta类封装了一些数据库的信息。主要字段如下:

1.db_table

  • 重命名表名,ORM在数据库中的表名默认是 app_类名,可以通过db_table可以重写表名

class Student(models.Model):
    username = models.CharField(max_length=10)
    age = models.IntegerField()

    def __str__(self):
        return 'username:{}, age:{}'.format(self.username, self.age)

    class Meta:
        db_table = 'student'

2.index_together

  • 联合索引

class Student(models.Model):
    username = models.CharField(max_length=10)
    age = models.IntegerField()

    def __str__(self):
        return 'username:{}, age:{}'.format(self.username, self.age)

    class Meta:
        index_together = ("username", "age")

3.unique_together

  • 联合唯一索引

class Student(models.Model):
    username = models.CharField(max_length=10)
    age = models.IntegerField()

    def __str__(self):
        return 'username:{}, age:{}'.format(self.username, self.age)

    class Meta:
        unique_together = ("username", "age")

4.ordering

  • 指定查询出来的数据默认按什么字段排序
  • 如果设置了该属性,我们查询到的结果可以直接使用 reverse(),而不需要先排序后再使用 reverse()
  • 在日常开发中不建议设置该属性

class Student(models.Model):
    username = models.CharField(max_length=10)
    age = models.IntegerField()

    def __str__(self):
        return 'username:{}, age:{}'.format(self.username, self.age)

    class Meta:
        ordering = ['id']  # 按id升序排列
# ordering = ['-id']  # 按id降序排列,-表示降序
        # ordering = ['?id']  # 随机排序,?表示随机
        # ordering = ['-age', 'id']  # 以age为降序,如果遇到相同数据再以id升序排列

5.abstract

  • 当 django 在进行数据迁移(即: 创建表)的时候,不再对该表进行创建

  • 作用: 当该model表设置了 abstract 参数,那么该model表可以当做“父类”,被其他 model 类继承

  • 注意: 如果该表类设置了 abstract 参数,那么该表类的外键字段和多对多字段的 to 参数的值必须是“类”,而不是一个字符串,否则就会报错

class User(models.Model):
    username = models.CharField(max_length=32, verbose_name='用户名')
    password = models.CharField(max_length=32, verbose_name='密码')
    roles = models.ManyToManyField(to=Role, verbose_name='角色')

    class Meta:
"""
        abstract = True 的介绍:
            django 在进行数据迁移的时候,不再对该表进行创建
            作用: 此类可以当做"父类",被其他Model类继承。
        """
abstract = True


class BackstageUserInfo(User):
    phone = models.CharField(max_length=32, null=True, blank=True, verbose_name='电话号码')
    age = models.IntegerField(verbose_name='年龄')
    gender_choices = (
        (1, '男'),
        (2, '女')
    )
    gender = models.IntegerField(choices=gender_choices, default=1, verbose_name='性别')

修改表


  • 直接对表的类进行修改就可以了,然后再执行那两条命令

  • 注意: 在对创建好的表添加新的字段的时候,如果表中有不能为空的字段或新添加的字段是不能为空的时候,当执行 python manage.py makemigrations 的时候就会报以下的错误 ->(意思就是: 需要你对不能为空的字段添加一个默认值

    • 解决办法: 选择选项1,然后填写默认值,且默认值是必填的,但是有的时候并不需要,可以用单引号代替('')

You are trying to add a non-nullable field 'username' to student without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)  # 选项1:填写该字段的默认值
2) Quit, and let me add a default in models.py  # 选项2: 退出,让我在models.py中添加默认值
Select an option:  填写: 选项(1,2)

删除表


  • 把需要的删除的表的类注释掉或删除掉,然后执行 makemigrations 和  migrate 命令